import tkinter as tk
from tkinter import StringVar
from typing import Callable

# 文本双击变输入框
class Label2Entry(tk.Label):
    def __init__(self, master,
                 str_var:StringVar,     # 同步变量到其他地方
                 limit_func:Callable[...,bool]=lambda:True,      # 输入函数限制text进行同步，符合条件才同步
                 layout='pack',
                 pack_kwargs=None,
                 grid_kwargs:dict=None,
                 **kwargs):
        super().__init__(master, **kwargs)
        # self.strTextVar = StringVar(value='空')
        if pack_kwargs is None:     # 参数预处理
            pack_kwargs = {}
        if grid_kwargs is None:
            grid_kwargs = {}

        self.layout = layout            # 布局方式与参数
        self.pack_kwargs = pack_kwargs
        self.grid_kwargs = grid_kwargs

        self.strTextVar = str_var
        self.func:Callable[...,bool] = limit_func     # 一个返回bool类型的参数


        self.bind('<Double-Button-1>', lambda e:self.show_entry())
        self.bind('Button-1', lambda e:self.focus_set())
        # 没有主界面，单独的界面与本label类同级。
        self.entry = tk.Entry(textvariable=self.strTextVar)
        self.entry.bind('<FocusOut>', lambda e:self.show_label())
        self.entry.bind('<Return>', lambda e: self.show_label())
        # 展示组件————内置布局底层
        self.widget_layout_show(self)

    # 自适应布局底层的方法
    def widget_layout_show(self,widget:tk.Widget=None):
        if self.layout in ('p','P','pack','PACK'):
            widget.pack(self.pack_kwargs)
        elif self.layout in ('g','G','grid','GRID'):
            widget.grid(self.grid_kwargs)

    def widget_layout_forget(self,widget:tk.Widget=None):
        if self.layout in ('p','P','pack','PACK'):
            widget.pack_forget()
        elif self.layout in ('g','G','grid','GRID'):
            widget.grid_forget()

    def show_entry(self):
        self.widget_layout_forget(self)
        self.widget_layout_show(self.entry)
        # self.pack_forget()
        # self.entry.pack()
        self.entry.focus_set()

    def show_label(self):
        if self.is_fresh_label():      # 如果条件OK
            self.config(text=self.entry.get())  # 将label的值与entry的值进行同步
        self.widget_layout_forget(self.entry)
        self.widget_layout_show(self)
        # self.entry.pack_forget()
        # self.pack()

    # 是否刷新label数值
    def is_fresh_label(self):
        return self.func()


if __name__ == '__main__':
    root = tk.Tk()
    strVar = StringVar(value='')
    label = Label2Entry(root, text='文本',str_var=strVar, layout='p', pack_kwargs={'side':'left'})
    # label.pack()
    root.mainloop()



